# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-08-05 23:05
# File     : logger.py
# Project  : codebuddy_craft
# Desc     : 功能完善的日志系统

# backend/utils/logger.py
"""
日志管理系统 📝

提供应用日志配置和管理功能
"""

import os
import sys
import logging
import logging.handlers
from pathlib import Path
from typing import Optional, Dict, Any
from datetime import datetime

try:
    import colorlog

    HAS_COLORLOG = True
except ImportError:
    HAS_COLORLOG = False

from backend.core.settings import Settings


class ColoredFormatter(logging.Formatter):
    """彩色日志格式化器 🌈"""

    # 颜色代码
    COLORS = {
        'DEBUG': '\033[36m',  # 青色
        'INFO': '\033[32m',  # 绿色
        'WARNING': '\033[33m',  # 黄色
        'ERROR': '\033[31m',  # 红色
        'CRITICAL': '\033[41m',  # 红色背景
        'RESET': '\033[0m'  # 重置
    }

    def format(self, record):
        """格式化日志记录"""
        if HAS_COLORLOG or hasattr(sys.stderr, 'isatty') and sys.stderr.isatty():
            # 添加颜色
            color = self.COLORS.get(record.levelname, self.COLORS['RESET'])
            record.levelname = f"{color}{record.levelname}{self.COLORS['RESET']}"

        return super().format(record)


class StructuredFormatter(logging.Formatter):
    """结构化日志格式化器 📊"""

    def format(self, record):
        """格式化为结构化JSON"""
        import json

        log_data = {
            'timestamp': datetime.fromtimestamp(record.created).isoformat(),
            'level': record.levelname,
            'logger': record.name,
            'message': record.getMessage(),
            'module': record.module,
            'function': record.funcName,
            'line': record.lineno
        }

        # 添加额外字段
        if hasattr(record, 'user_id'):
            log_data['user_id'] = record.user_id
        if hasattr(record, 'request_id'):
            log_data['request_id'] = record.request_id
        if hasattr(record, 'ip_address'):
            log_data['ip_address'] = record.ip_address

        # 异常信息
        if record.exc_info:
            log_data['exception'] = self.formatException(record.exc_info)

        return json.dumps(log_data, ensure_ascii=False)


class RequestIDFilter(logging.Filter):
    """请求ID过滤器 🔍"""

    def filter(self, record):
        """添加请求ID到日志记录"""
        # 尝试从上下文获取请求ID
        try:
            from contextvars import ContextVar
            request_id_var: ContextVar = ContextVar('request_id', default=None)
            record.request_id = request_id_var.get()
        except:
            record.request_id = None

        return True


class SQLAlchemyFilter(logging.Filter):
    """SQLAlchemy日志过滤器 🗄️"""

    def filter(self, record):
        """过滤SQLAlchemy的重复日志"""
        # 过滤掉一些重复的SQL日志
        if record.name.startswith('sqlalchemy.engine'):
            # 只记录错误和警告
            return record.levelno >= logging.WARNING
        return True


def setup_logging(settings: Settings) -> None:
    """设置日志系统 📝

    Args:
        settings: 应用配置
    """

    # 清除现有的处理器
    root_logger = logging.getLogger()
    for handler in root_logger.handlers[:]:
        root_logger.removeHandler(handler)

    # 设置根日志级别
    root_logger.setLevel(getattr(logging, settings.LOG_LEVEL.upper()))

    # 创建日志目录
    if settings.LOG_FILE:
        log_path = Path(settings.LOG_FILE)
        log_path.parent.mkdir(parents=True, exist_ok=True)

    # 设置日志格式
    console_format = get_console_format(settings)
    file_format = get_file_format(settings)

    # 控制台处理器
    console_handler = create_console_handler(console_format, settings)
    if console_handler:
        root_logger.addHandler(console_handler)

    # 文件处理器
    if settings.LOG_FILE:
        file_handler = create_file_handler(settings.LOG_FILE, file_format, settings)
        if file_handler:
            root_logger.addHandler(file_handler)

        # 错误日志文件
        error_handler = create_error_handler(settings.LOG_FILE, file_format, settings)
        if error_handler:
            root_logger.addHandler(error_handler)

    # 配置特定日志记录器
    configure_loggers(settings)

    # 记录启动信息
    logger = logging.getLogger(__name__)
    logger.info(f"🚀 日志系统已初始化 (级别: {settings.LOG_LEVEL})")

    if settings.LOG_FILE:
        logger.info(f"📁 日志文件: {settings.LOG_FILE}")


def get_console_format(settings: Settings) -> str:
    """获取控制台日志格式 🖥️"""
    if settings.is_development:
        return "%(asctime)s | %(levelname)-8s | %(name)-25s | %(message)s"
    else:
        return "%(asctime)s | %(levelname)-8s | %(message)s"


def get_file_format(settings: Settings) -> str:
    """获取文件日志格式 📄"""
    return "%(asctime)s | %(levelname)-8s | %(name)-30s | %(funcName)-20s:%(lineno)-3d | %(message)s"


def create_console_handler(format_str: str, settings: Settings) -> Optional[logging.Handler]:
    """创建控制台处理器 🖥️"""
    try:
        handler = logging.StreamHandler(sys.stdout)
        handler.setLevel(getattr(logging, settings.LOG_LEVEL.upper()))

        # 使用彩色格式化器
        if HAS_COLORLOG and settings.is_development:
            formatter = colorlog.ColoredFormatter(
                '%(log_color)s%(asctime)s | %(levelname)-8s%(reset)s | '
                '%(blue)s%(name)-25s%(reset)s | %(message)s',
                datefmt='%H:%M:%S',
                log_colors={
                    'DEBUG': 'cyan',
                    'INFO': 'green',
                    'WARNING': 'yellow',
                    'ERROR': 'red',
                    'CRITICAL': 'red,bg_white',
                }
            )
        else:
            formatter = ColoredFormatter(
                format_str,
                datefmt='%Y-%m-%d %H:%M:%S'
            )

        handler.setFormatter(formatter)

        # 添加过滤器
        handler.addFilter(RequestIDFilter())

        return handler

    except Exception as e:
        print(f"❌ 创建控制台日志处理器失败: {e}")
        return None


def create_file_handler(log_file: str, format_str: str, settings: Settings) -> Optional[logging.Handler]:
    """创建文件处理器 📄"""
    try:
        # 使用轮转文件处理器
        handler = logging.handlers.TimedRotatingFileHandler(
            filename=log_file,
            when='midnight',  # 每天轮转
            interval=1,
            backupCount=30,  # 保留30天
            encoding='utf-8',
            delay=True
        )

        handler.setLevel(logging.DEBUG)

        # 根据环境选择格式化器
        if settings.is_production:
            formatter = StructuredFormatter()
        else:
            formatter = logging.Formatter(
                format_str,
                datefmt='%Y-%m-%d %H:%M:%S'
            )

        handler.setFormatter(formatter)

        # 添加过滤器
        handler.addFilter(RequestIDFilter())

        return handler

    except Exception as e:
        print(f"❌ 创建文件日志处理器失败: {e}")
        return None


def create_error_handler(log_file: str, format_str: str, settings: Settings) -> Optional[logging.Handler]:
    """创建错误日志处理器 ❌"""
    try:
        # 错误日志文件路径
        error_log_file = log_file.replace('.log', '_error.log')

        handler = logging.handlers.TimedRotatingFileHandler(
            filename=error_log_file,
            when='midnight',
            interval=1,
            backupCount=90,  # 错误日志保留更久
            encoding='utf-8',
            delay=True
        )

        # 只记录错误和严重错误
        handler.setLevel(logging.ERROR)

        formatter = logging.Formatter(
            format_str,
            datefmt='%Y-%m-%d %H:%M:%S'
        )

        handler.setFormatter(formatter)
        handler.addFilter(RequestIDFilter())

        return handler

    except Exception as e:
        print(f"❌ 创建错误日志处理器失败: {e}")
        return None


def configure_loggers(settings: Settings) -> None:
    """配置特定的日志记录器 ⚙️"""

    # SQLAlchemy日志配置
    sqlalchemy_logger = logging.getLogger('sqlalchemy')
    if settings.DATABASE_ECHO:
        sqlalchemy_logger.setLevel(logging.INFO)
    else:
        sqlalchemy_logger.setLevel(logging.WARNING)
        sqlalchemy_logger.addFilter(SQLAlchemyFilter())

    # HTTP客户端日志
    urllib3_logger = logging.getLogger('urllib3')
    urllib3_logger.setLevel(logging.WARNING)

    # FastAPI日志配置
    uvicorn_logger = logging.getLogger('uvicorn')
    uvicorn_logger.setLevel(logging.INFO)

    # 自定义应用日志
    app_logger = logging.getLogger('backend')
    app_logger.setLevel(getattr(logging, settings.LOG_LEVEL.upper()))

    # 如果是生产环境，降低一些第三方库的日志级别
    if settings.is_production:
        noisy_loggers = [
            'urllib3.connectionpool',
            'requests.packages.urllib3',
            'asyncio',
            'concurrent.futures'
        ]

        for logger_name in noisy_loggers:
            logger = logging.getLogger(logger_name)
            logger.setLevel(logging.WARNING)


def get_logger(name: str) -> logging.Logger:
    """获取日志记录器 📝

    Args:
        name: 日志记录器名称

    Returns:
        配置好的日志记录器
    """
    return logging.getLogger(name)


class LoggerMixin:
    """日志记录器混入类 🔄"""

    @property
    def logger(self) -> logging.Logger:
        """获取当前类的日志记录器"""
        return get_logger(f"{self.__class__.__module__}.{self.__class__.__name__}")


def log_execution_time(func_name: str = None):
    """记录函数执行时间装饰器 ⏱️"""

    def decorator(func):
        import functools
        import time

        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            name = func_name or f"{func.__module__}.{func.__name__}"
            logger = get_logger(name)

            start_time = time.time()
            try:
                result = func(*args, **kwargs)
                execution_time = time.time() - start_time
                logger.debug(f"⏱️ {name} 执行时间: {execution_time:.3f}s")
                return result
            except Exception as e:
                execution_time = time.time() - start_time
                logger.error(f"❌ {name} 执行失败 (时间: {execution_time:.3f}s): {e}")
                raise

        return wrapper

    return decorator


def log_async_execution_time(func_name: str = None):
    """记录异步函数执行时间装饰器 ⏱️"""

    def decorator(func):
        import functools
        import asyncio
        import time

        @functools.wraps(func)
        async def wrapper(*args, **kwargs):
            name = func_name or f"{func.__module__}.{func.__name__}"
            logger = get_logger(name)

            start_time = time.time()
            try:
                result = await func(*args, **kwargs)
                execution_time = time.time() - start_time
                logger.debug(f"⏱️ {name} 执行时间: {execution_time:.3f}s")
                return result
            except Exception as e:
                execution_time = time.time() - start_time
                logger.error(f"❌ {name} 执行失败 (时间: {execution_time:.3f}s): {e}")
                raise

        return wrapper

    return decorator


class ContextLogger:
    """上下文日志记录器 📋"""

    def __init__(self, logger: logging.Logger, **context):
        self.logger = logger
        self.context = context

    def _log(self, level: int, message: str, *args, **kwargs):
        """记录日志并添加上下文信息"""
        # 创建日志记录
        record = self.logger.makeRecord(
            self.logger.name, level, "", 0, message, args, None
        )

        # 添加上下文信息
        for key, value in self.context.items():
            setattr(record, key, value)

        # 添加额外的关键字参数
        for key, value in kwargs.items():
            setattr(record, key, value)

        self.logger.handle(record)

    def debug(self, message: str, *args, **kwargs):
        """记录调试日志"""
        self._log(logging.DEBUG, message, *args, **kwargs)

    def info(self, message: str, *args, **kwargs):
        """记录信息日志"""
        self._log(logging.INFO, message, *args, **kwargs)

    def warning(self, message: str, *args, **kwargs):
        """记录警告日志"""
        self._log(logging.WARNING, message, *args, **kwargs)

    def error(self, message: str, *args, **kwargs):
        """记录错误日志"""
        self._log(logging.ERROR, message, *args, **kwargs)

    def critical(self, message: str, *args, **kwargs):
        """记录严重错误日志"""
        self._log(logging.CRITICAL, message, *args, **kwargs)


def get_context_logger(name: str, **context) -> ContextLogger:
    """获取上下文日志记录器 📋

    Args:
        name: 日志记录器名称
        **context: 上下文信息

    Returns:
        上下文日志记录器
    """
    logger = get_logger(name)
    return ContextLogger(logger, **context)


# 性能监控日志
class PerformanceLogger:
    """性能监控日志记录器 📊"""

    def __init__(self, name: str):
        self.logger = get_logger(f"performance.{name}")
        self.metrics = {}

    def record_metric(self, name: str, value: float, unit: str = ""):
        """记录性能指标"""
        self.metrics[name] = {"value": value, "unit": unit}
        self.logger.info(f"📊 {name}: {value}{unit}")

    def record_duration(self, name: str, duration: float):
        """记录执行时长"""
        self.record_metric(name, duration, "ms")

    def record_counter(self, name: str, count: int):
        """记录计数器"""
        self.record_metric(name, count, "次")

    def flush_metrics(self):
        """输出所有指标"""
        if self.metrics:
            self.logger.info(f"📈 性能指标汇总: {self.metrics}")
            self.metrics.clear()


def get_performance_logger(name: str) -> PerformanceLogger:
    """获取性能监控日志记录器 📊"""
    return PerformanceLogger(name)


# 安全日志
class SecurityLogger:
    """安全事件日志记录器 🔒"""

    def __init__(self):
        self.logger = get_logger("security")

    def log_auth_attempt(self, username: str, ip_address: str, success: bool, **kwargs):
        """记录认证尝试"""
        status = "成功" if success else "失败"
        self.logger.info(
            f"🔐 认证{status}: 用户={username}, IP={ip_address}",
            extra={
                "event_type": "auth_attempt",
                "username": username,
                "ip_address": ip_address,
                "success": success,
                **kwargs
            }
        )

    def log_permission_denied(self, user_id: str, resource: str, action: str, **kwargs):
        """记录权限拒绝"""
        self.logger.warning(
            f"🚫 权限拒绝: 用户={user_id}, 资源={resource}, 操作={action}",
            extra={
                "event_type": "permission_denied",
                "user_id": user_id,
                "resource": resource,
                "action": action,
                **kwargs
            }
        )

    def log_suspicious_activity(self, description: str, **kwargs):
        """记录可疑活动"""
        self.logger.warning(
            f"⚠️ 可疑活动: {description}",
            extra={
                "event_type": "suspicious_activity",
                "description": description,
                **kwargs
            }
        )


def get_security_logger() -> SecurityLogger:
    """获取安全日志记录器 🔒"""
    return SecurityLogger()
